Skip to content

Bugfix/issue 86 image upload assets not immediately available#156

Merged
manuelkiessling merged 5 commits intomainfrom
bugfix/issue-86-image-upload-assets-not-immediately-available
Feb 26, 2026
Merged

Bugfix/issue 86 image upload assets not immediately available#156
manuelkiessling merged 5 commits intomainfrom
bugfix/issue-86-image-upload-assets-not-immediately-available

Conversation

@schramm-joboo
Copy link
Contributor

@schramm-joboo schramm-joboo commented Feb 25, 2026

Issue #86

When uploaded, assets are not immediately available and the upload status is unknown as long as it takes for uploading and processing.


Note

Medium Risk
Adds polling/background-sync and new API response fields, which changes client/server contract and introduces timing-driven behavior that could affect UX and load if misconfigured.

Overview
Fixes remote asset uploads not appearing immediately by tracking a manifest revision and waiting for uploaded files to show up in the manifest before prompting the user to refresh.

The GET /api/projects/{projectId}/remote-assets response now includes revision (sha256 over sorted URLs), and the Stimulus remote-asset-browser adds manifest polling (including focus/visibility/background checks), a new processing/refresh prompt UI state with confirm/dismiss actions, and updated error/partial-failure messaging. Frontend unit tests and en/de translations are updated to cover and label the new behaviors.

Written by Cursor Bugbot for commit 6419900. This will update automatically on new commits. Configure here.

@schramm-joboo schramm-joboo self-assigned this Feb 25, 2026
@schramm-joboo schramm-joboo marked this pull request as draft February 25, 2026 08:13
@manuelkiessling
Copy link
Member

@schramm-joboo

As discussed, I think a good UX would be to continously poll for changes on the manifest, and if a delta between the manifest content and our UI state is detected, then don't do an automatic refresh of the assets browser (which could be unnerving if a user is using the browser in that moment), but instead present an info bubble which says that the content on the image server has changed, and offer a call-to-action to manually refresh the browser.

@manuelkiessling manuelkiessling self-requested a review February 25, 2026 08:41
@schramm-joboo
Copy link
Contributor Author

schramm-joboo commented Feb 26, 2026

@manuelkiessling I've implemented a subtle info bubble which asks whether to re-render the image list or not.

@manuelkiessling manuelkiessling force-pushed the bugfix/issue-86-image-upload-assets-not-immediately-available branch from f2cad9e to 45c3458 Compare February 26, 2026 14:15
- Implemented immediate image access after upload; manifest.json is updated later
- Former solution removed; As long as the manifest.json has not been updated, a message is being displayed that the images are being processed. As soon as the manifest.json update is finished, the image list is updated
- Steady silent polling in case images have been deleted on the remote server
- Reload image list only if desired
@manuelkiessling manuelkiessling force-pushed the bugfix/issue-86-image-upload-assets-not-immediately-available branch from 45c3458 to 96b5c92 Compare February 26, 2026 14:28
- Use messages YAML files for display of messages instead of hard-coded messages
@manuelkiessling manuelkiessling marked this pull request as ready for review February 26, 2026 16:34
@manuelkiessling manuelkiessling merged commit 49fbee2 into main Feb 26, 2026
9 of 12 checks passed
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Free Tier Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Bugbot Autofix prepared fixes for all 3 issues found in the latest run.

  • ✅ Fixed: Success message shown even when fetch fails
    • reloadAssetsAfterConfirmation now returns early when fetchAssets() returns null, so success UI is shown only after a successful refresh.
  • ✅ Fixed: Stale DOM text used as fallback error label
    • The fallback upload error label is now captured once from the initial DOM text on connect and reused, avoiding stale overwritten error messages.
  • ✅ Fixed: Spurious refresh prompt when revision is initially null
    • checkForManifestUpdates now skips checks while isLoading is true, preventing refresh prompts during the initial manifest load race.

Create PR

Or push these changes by commenting:

@cursor push 7aea7a69f6
Preview (7aea7a69f6)
diff --git a/src/RemoteContentAssets/Presentation/Resources/assets/controllers/remote_asset_browser_controller.ts b/src/RemoteContentAssets/Presentation/Resources/assets/controllers/remote_asset_browser_controller.ts
--- a/src/RemoteContentAssets/Presentation/Resources/assets/controllers/remote_asset_browser_controller.ts
+++ b/src/RemoteContentAssets/Presentation/Resources/assets/controllers/remote_asset_browser_controller.ts
@@ -104,6 +104,7 @@
     private backgroundSyncTimeoutId: ReturnType<typeof setTimeout> | null = null;
     private latestManifestRevision: string | null = null;
     private isBackgroundSyncEnabled: boolean = false;
+    private uploadErrorFallbackLabel: string = "Upload failed. Please try again.";
     private readonly focusHandler = (): void => {
         void this.checkForManifestUpdates();
     };
@@ -115,6 +116,13 @@
 
     connect(): void {
         this.isConnected = true;
+        if (this.hasUploadErrorTarget) {
+            const textEl = this.uploadErrorTarget.querySelector("[data-error-text]");
+            const initialText = textEl?.textContent?.trim();
+            if (initialText) {
+                this.uploadErrorFallbackLabel = initialText;
+            }
+        }
         void this.fetchAssets();
         this.setupDropzone();
         this.isBackgroundSyncEnabled = this.getBackgroundSyncIntervalMs() > 0;
@@ -513,7 +521,7 @@
     }
 
     private async checkForManifestUpdates(): Promise<void> {
-        if (this.isUploading) {
+        if (this.isUploading || this.isLoading) {
             return;
         }
 
@@ -560,7 +568,9 @@
     }
 
     private async reloadAssetsAfterConfirmation(): Promise<void> {
-        await this.fetchAssets();
+        if ((await this.fetchAssets()) === null) {
+            return;
+        }
         this.showUploadStatus("success");
         setTimeout(() => this.showUploadStatus("none"), 3000);
     }
@@ -572,13 +582,7 @@
     }
 
     private getUploadErrorFallbackLabel(): string {
-        if (this.hasUploadErrorTarget) {
-            const textEl = this.uploadErrorTarget.querySelector("[data-error-text]");
-            if (textEl && textEl.textContent !== null && textEl.textContent !== "") {
-                return textEl.textContent;
-            }
-        }
-        return "Upload failed. Please try again.";
+        return this.uploadErrorFallbackLabel;
     }
 
     private normalizeManifestData(data: { urls?: string[]; revision?: string }): { urls: string[]; revision: string } {
This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

await this.fetchAssets();
this.showUploadStatus("success");
setTimeout(() => this.showUploadStatus("none"), 3000);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Success message shown even when fetch fails

Medium Severity

reloadAssetsAfterConfirmation always shows the "success" status after calling fetchAssets(), regardless of whether the fetch succeeded or failed. Since fetchAssets returns null on failure, the return value can be checked — but it's currently ignored. If the network request fails when the user confirms a refresh, they'll see the empty state alongside a contradictory "Upload complete." success message.

Fix in Cursor Fix in Web

}
}
return "Upload failed. Please try again.";
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale DOM text used as fallback error label

Low Severity

getUploadErrorFallbackLabel reads the current text content of the [data-error-text] element in the DOM. After any prior call to showUploadError, this element retains the previous error message (e.g., "1 of 3 uploads failed." or "still processing"). On a subsequent all-fail upload, this stale text is returned instead of the intended generic fallback, showing the user an incorrect or confusing error message.

Fix in Cursor Fix in Web

if (currentRevision === null || manifestData.revision !== currentRevision) {
this.latestManifestRevision = manifestData.revision;
this.markRefreshAvailable();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spurious refresh prompt when revision is initially null

Low Severity

checkForManifestUpdates treats currentRevision === null as a manifest change, triggering a refresh prompt. Since latestManifestRevision starts as null and is only set once fetchAssets completes, any focus or visibilitychange event that fires before that (e.g., user switches to a background-loaded tab) would cause a spurious "New images are available" prompt over content that was just loaded. The method guards against isUploading but not isLoading.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants